use std::collections::HashMap;

use crate::data::{DataValue, RowField, RowsetOwner};

pub struct MapUtil;

impl MapUtil {
    pub fn get_string<'a>(
        map: &'a HashMap<String, RowField>,
        key: &str,
        default_value: &'a str,
    ) -> &'a str {
        Self::get_string_with_depend(map, key, default_value, None)
    }

    pub fn get_string_with_depend<'a>(
        map: &'a HashMap<String, RowField>,
        key: &str,
        default_value: &'a str,
        depend_rowset: Option<&'a RowsetOwner>,
    ) -> &'a str {
        if let Some(value) = Self::get_object_with_depend(map, key, depend_rowset) {
            if let RowField::Value(DataValue::String(inner)) = value {
                return inner.as_str();
            }
        }
        default_value
    }

    pub fn get_object<'a>(map: &'a HashMap<String, RowField>, key: &str) -> Option<&'a RowField> {
        Self::get_object_with_depend(map, key, None)
    }

    pub fn get_object_mut<'a>(
        map: &'a mut HashMap<String, RowField>,
        key: &str,
    ) -> Option<&'a mut RowField> {
        Self::get_object_with_depend_mut(map, key, None)
    }

    pub fn get_object_with_depend<'a>(
        map: &'a HashMap<String, RowField>,
        key: &str,
        depend_rowset: Option<&'a RowsetOwner>,
    ) -> Option<&'a RowField> {
        map.get(key).or_else(|| {
            if let Some(depend) = depend_rowset {
                depend.get_object(key)
            } else {
                None
            }
        })
    }

    pub fn get_object_with_depend_mut<'a>(
        map: &'a mut HashMap<String, RowField>,
        key: &str,
        depend_rowset: Option<&'a mut RowsetOwner>,
    ) -> Option<&'a mut RowField> {
        map.get_mut(key).or_else(|| {
            if let Some(depend) = depend_rowset {
                depend.get_object_mut(key)
            } else {
                None
            }
        })
    }
}
